package controllers;

import java.util.*;

import play.mvc.*;
import play.data.*;
import static play.data.Form.*;
import play.*;

import views.html.passerQCM.*;

import models.*;

/**
 * @author jubonnea
 * 
 */
public abstract class PasserQCM extends Controller {
	/**
	 * la fonction permet de lister l'ensemble des QCM
	 * 
	 * @return une vue prenant en paramètre tous les Qcm présents en BD
	 */
	public static Result listeQCM() {
		final Qcm q = new Qcm();
		return ok(listeQcm.render(Qcm.findAll(), q, ""));
	}

	/**
	 * la fonction permet de vérifier si lahe clé saisie pr passer le QCM est OK
	 * 
	 * @return la premiere question si la clé est correcte sinon on reste sur la
	 *         page et un msg d'erreur s'affichz
	 */
	public static Result authentificationQcm() {

		final DynamicForm dynamicForm = form().bindFromRequest();
		final Qcm qcm = Qcm.findById(Long.parseLong(dynamicForm.get("idQcm")));
		final String cle = dynamicForm.get("cleQcm");
		if (qcm.getCleAuthentification().equals(cle)) {
			Logger.debug("Acces au QCM : Id = " + qcm.getIdQcm()
					+ " Libelle = " + qcm.getLibelle() + " par user "
					+ session().get("id"));
			// permet d'afficher la page expliquant les regles
			return ok(regle.render(qcm));
		} else {
			return ok(listeQcm.render(Qcm.findAll(), qcm,
					"La cle saisie est incorrecte veuillez réessayer"));
		}
	}

	// contient la liste de question rangé de façon aléatoire, et accessible
	// depuis toutes les méthodes de la classe
	protected static Map<Integer, Question> tableauQuestion;

	/**
	 * Permet de rendre aléatoire l'ordre des questions.
	 * la fonction prend en paramètre un id et récupère 
	 * l'UtilisateurQcm correspondant à cet ID elle va 
	 * permettre d'initaliser l'UtilisateurQcm a partir de l'id de
	 * l'étudiant en session et le QCM sélectionné
	 * 
	 * @return la question suivante
	 */
	public static Map<Integer, Question> melangerQuestions(final Long id) {

		tableauQuestion = new HashMap<Integer, Question>();

		final Qcm QcmDetails = Qcm.findById(id);

		// on cree une liste dans laquelle des entiers allant de 0 au nombre de
		// question d'un QCM - 1
		final List<Integer> listAleatoire = new ArrayList<Integer>();
		for (int i = 0; i < QcmDetails.getListeQuestions().size(); i++) {
			listAleatoire.add(i);
		}
		// on mélange tous ces chiffres de façon aléatoire afin d'obtenir une
		// liste aléatoire
		Collections.shuffle(listAleatoire);

		int j = 0;
		// on constitue la map : en associant valeur du jeme élement de la liste
		// avec une question
		while (j < QcmDetails.getListeQuestions().size()) {
			for (Question q : QcmDetails.getListeQuestions()) {
				tableauQuestion.put(listAleatoire.get(j), q);
				j++;
			}
		}
		return tableauQuestion;

	}

	/**
	 * la fonction prend en paramètre un id et récupère le QCM correspondant à
	 * cet ID elle va permettre de commencer à passer un Qcm.
	 * 
	 * @return une vue prenant en paramètre le Qcm correspondant à l'id
	 */
	public static Result debutQCM(final Long id) {
		final Qcm QcmDetails = Qcm.findById(id);
		final DynamicForm filledForm = form().bindFromRequest();
		if ("home".equals(filledForm.field("action").value())) {
			return redirect(routes.PasserQCM.listeQCM());
		} else {
			// on retourne directement une Map de questions rangées de façon
			// aléatoire
		    session("cptQuestion", "0");
			return ok(debQcm.render(QcmDetails,
					melangerQuestions(QcmDetails.getIdQcm())));
		}
	}

	/**
	 * la fonction prend en paramètre un id et récupère l'UtilisateurQcm correspondant
	 * à cet ID elle va permettre d'initaliser l'UtilisateurQcm a partir de l'id de
	 * l'étudiant en session et le QCM sélectionné
	 * 
	 * @return la question suivante
	 */
	public static Result initialisationUtilisateurQcm(final Long id) {
	    Logger.debug("Id Qcm : " + String.valueOf(id));
		final Qcm qcmRep = Qcm.findById(id);

		
		
		

		final Utilisateur us = Utilisateur.findById(Long.parseLong(session("id")));
		
		UtilisateurQcm utilisateurQcm = UtilisateurQcm.findByIds(id, us.getIdUtilisateur());
		if(utilisateurQcm == null){
		    utilisateurQcm = new UtilisateurQcm();
		    utilisateurQcm.setUtilisateur(us);
            utilisateurQcm.setQcm(qcmRep);
            utilisateurQcm.setDate(new GregorianCalendar().getTime());
            utilisateurQcm.save();
		}

		return questionSuivanteQCM(utilisateurQcm.getIdUtilisateurQcm());
	}

	/**
	 * la fonction prend en paramètre un id et récupère l'UtilisateurQcm correspondant
	 * à cet ID elle va permettre d'afficher la question suivante tant qu'il y a
	 * des questions restantes
	 * 
	 * @return la question suivante ou si c'est la fin la fct calcule la note
	 */
	public static Result questionSuivanteQCM(final Long id) {

		final UtilisateurQcm utilisateurQcm = UtilisateurQcm.findById(id);

		final DynamicForm dynamicForm = form().bindFromRequest();
		// on récupere le numero du compteur numQ
		int numQ = Integer.parseInt(dynamicForm.get("numQ"));
		

		// on cherche dans la map la question associée a ce compteur
		final Question q = tableauQuestion.get(numQ);
		Choix choix, choixUtilisateur;
		
		int numQSession = Integer.parseInt(session("cptQuestion"));
        if(numQ != numQSession){
            Logger.debug("Retour sur question antérieure");
            return ok(questionQcm.render(numQSession, utilisateurQcm, tableauQuestion, "Impossible de revenir à la question précédente"));
        }

		// on enregistre la liste des choix du user dans userQCM
		final Iterator<Choix> itc = q.getListeChoix().iterator();
		while (itc.hasNext()) {
			choix = (Choix) itc.next();
			if (dynamicForm.get("Choix" + choix.getIdChoix()) != null) {
				choixUtilisateur = Choix.findById(Long.parseLong(dynamicForm
						.get("Choix" + choix.getIdChoix())));
				if (choixUtilisateur != null) {
					utilisateurQcm.getListeChoixUtilisateur().add(choixUtilisateur);
				}
			}
		}
		// on sauvegarde dans la base de données
		UtilisateurQcm.update(utilisateurQcm);

		// si le compteur numQ est différent de la taille de la map contenant
		// toutes les question - 1
		if (numQ != tableauQuestion.size() - 1) {
			// alors on incremente le compteur et on passe à la question
			// suivante
			numQ++;
			session("cptQuestion", String.valueOf(numQ));
			Logger.debug("Incremantation Question");
			return ok(questionQcm.render(numQ, utilisateurQcm, tableauQuestion, ""));
		} else {

			// sinon les QCM est terminé on passe au calcul de la note

			utilisateurQcm.setDuree((int) (new Date().getTime() - utilisateurQcm.getDate()
					.getTime()) / 1000 / 60);
			UtilisateurQcm.update(utilisateurQcm);

			return calculNote(id);
		}
	}

	/**
	 * la fonction prend en paramètre un id de l'étudiant et l'id du Qcm elle
	 * affiche : 1 si la question répondue par l'étudiant est bonne, -1 si la
	 * question répondue est fausse et 0 si l'étudiant n'a pas répondu à la
	 * question.
	 * 
	 * @return une Map contenant pour chaque question du Qcm la valeur 1, -1 ou
	 *         0
	 */
	public static Map<Question, Double> correction(final Long idUtilisateur,
			final Long idQcm) {
		final Map<Question, Double> repUtilisateur = new HashMap<Question, Double>();
		final UtilisateurQcm utilisateurQcm = UtilisateurQcm.findByIds(idQcm, idUtilisateur);
		Question question;
		Choix choix;
		int cpt_repUtilisateur;
		int cpt_repJuste;

		final Iterator<Question> itq = utilisateurQcm.getQcm().getListeQuestions()
				.iterator();
		while (itq.hasNext()) {
			question = itq.next();
			final Iterator<Choix> itc = question.getListeChoix().iterator();
			cpt_repUtilisateur = 0;
			cpt_repJuste = 0;
			while (itc.hasNext()) {
				choix = itc.next();
				if (choix.getEstVrai()) {
					cpt_repJuste++;
					if (utilisateurQcm.getListeChoixUtilisateur().contains(choix)) {
						cpt_repUtilisateur++;
					}
				} else {
					if (utilisateurQcm.getListeChoixUtilisateur().contains(choix)) {
						cpt_repUtilisateur = -1;
						repUtilisateur.put(question, -1.0);
						break;
					}
				}
			}
			if (cpt_repUtilisateur != -1) {
				if (cpt_repUtilisateur == 0) {
					repUtilisateur.put(question, 0.00);
				} else if (cpt_repUtilisateur == cpt_repJuste) {
					repUtilisateur.put(question, 1.00);
				} else if (cpt_repUtilisateur != cpt_repJuste) {
					repUtilisateur.put(question, -1.00);
				}
			}
		}
		return repUtilisateur;
	}

	/**
	 * la fonction prend en paramètre un id et récupère l'UtilisateurQcm correspondant
	 * à cet ID elle va permettre de calculer la note de l'étudiant pour un Qcm
	 * à partir de la map revoyée par la fonction correction
	 * 
	 * @return la question l'étudiant Qcm et la Map correction
	 */
	public static Result calculNote(final Long id) {
		Double noteFinale = 0.0;
		Double total = 0.0;
		final UtilisateurQcm utilisateurQcm = UtilisateurQcm.findById(id);
		final Map<Question, Double> correct = correction(utilisateurQcm.getUtilisateur()
				.getIdUtilisateur(), utilisateurQcm.getQcm().getIdQcm());

		for (Question question : utilisateurQcm.getQcm().getListeQuestions()) {
			total += utilisateurQcm.getQcm()
					.findQcmNiveauQuestion(question.getNiveauQuestion())
					.getPointPositif();

			// si la reponse à la question est bonne
			if (correct.get(question) == 1) {
				// on ajoute les points positifs correspondant à la question
				noteFinale += utilisateurQcm.getQcm()
						.findQcmNiveauQuestion(question.getNiveauQuestion())
						.getPointPositif();
			} else if (correct.get(question) == -1) { // si la reponse à la
														// question est fausse
				// on reture les points negatifs correspondant à la question
				noteFinale -= utilisateurQcm.getQcm()
						.findQcmNiveauQuestion(question.getNiveauQuestion())
						.getPointNegatif();
			}
		}

		// si la note est négative on la ramène à 0
		if (noteFinale < 0) {
			noteFinale = 0.0;
		}

		// ramène la note finale sur 20
		utilisateurQcm.setNote((noteFinale * 20) / total);

		utilisateurQcm.save();
		Logger.debug("Validation du QCM : Id = " + utilisateurQcm.getQcm().getIdQcm()
				+ " Libelle = " + utilisateurQcm.getQcm().getLibelle()
				+ " par user : id = " + utilisateurQcm.getUtilisateur().getIdUtilisateur()
				+ " Nom = " + utilisateurQcm.getUtilisateur().getNom() + " Prénom = "
				+ utilisateurQcm.getUtilisateur().getPrenom());

		// A SUPPRIMER ??
		// StringBuilder s= new StringBuilder();
		// s.append("Vos réponse ont bien été enregistrée. \n Vos résultats seront disponibles losque le professeur aura validé le QCM.");
		// return Application.redirectionAccueil(s.toString());

		return ok(finQcm.render(utilisateurQcm, correct));

	}

	public static Result listeMesQCM() {
		final Utilisateur us = Utilisateur.findById(Long.parseLong(session("id")));
		return ok(listeMesQcm.render(us.getListeQcmPasses()));
	}

	public static Result correctionQcm(final Long id) {
		final Qcm qcmRep = Qcm.findById(id);
		final Utilisateur us = Utilisateur.findById(Long.parseLong(session("id")));

		final UtilisateurQcm utilisateurQcm = UtilisateurQcm.findByIds(qcmRep.getIdQcm(),
				us.getIdUtilisateur());
		return calculNote(utilisateurQcm.getIdUtilisateurQcm());
	}

}